#define _GNU_SOURCE
#include "app_device.h"

#include "unistd.h"
#include "fcntl.h"
#include "pthread.h"
#include "app_pool.h"
#include "app_message.h"
#include "app_mqtt.h"

Device *device = NULL; /* 全局变量，程序更好写*/

/*==============回调函数部分 上================================================================*/

/**
 * @brief 注册线程回调函数
 *
 * @param arg 蓝牙设备结构体
 */
void pthreads_BlueTask(void *arg)
{
    /* 获得串口设备结构体 */
    Device *device = (Device *)arg;
    char tmpBuff[128] = {0};

    /* 1.从上行缓冲区里读取字符数组数据 */
    int data_len = app_buffer_read(device->up_buffer, tmpBuff, sizeof(tmpBuff));
    if (data_len == -1)
    {
        log_error("读取失败");
        return;
    }

    /* 2.将数据转为Json数据 */
    char jsonBuff[128] = {0};
    if (app_message_chars2json(tmpBuff, jsonBuff) == ERROR)
    {
        log_error("数据转换失败");
        return;
    }

    /* 3.通过MQTT协议发送到上行服务器 */
    if (app_mqtt_publish(jsonBuff, strlen(jsonBuff)) == ERROR)
    {
        log_error("发送失败");
        return;
    }
}

/**
 * @brief 注册线程回调函数
 *
 * @param arg 蓝牙设备结构体
 */
void pthreads_MqttTask(void *arg)
{
    /* 获得串口设备结构体 */
    Device *device = (Device *)arg;
    char tmpBuff[128] = {0};
    /* 1.从下行缓冲区里读取字符数组数据 */
    int data_len = app_buffer_read(device->down_buffer, tmpBuff, sizeof(tmpBuff));
    if (data_len == -1)
    {
        log_error("读取失败");
        return;
    }

    /* 2.将数据转为蓝牙帧数据 */
    data_len = device->pre_write(tmpBuff, data_len);
    if (data_len == -1)
    {
        log_error("数据转换失败");
        return;
    }

    /* note:
     限制两次写入间隔时间不能小于200ms
     */

    long distance = app_common_getCurTime() - device->last_write_time;
    if (distance < 200)
    {
        usleep(200000 - distance * 1000); /* 200ms = 200000us    distance * 1000= us */
    }

    /* 3.通过串口发送到设备 */
    ssize_t result = write(device->fd, tmpBuff, data_len);
    if (result == -1)
    {
        log_error("发送失败");
        return;
    }

    // 更新最后写入时间
    device->last_write_time = app_common_getCurTime(); /* ms*/
}

/**
 * @brief 这个线程干嘛的？: 通过串口读取下行设备信息（BL)发送到上行缓存
 *
 * @param arg
 */
void * receive_BlueData_callback(void *arg)
{
    /* 获得串口设备结构体 */
    Device *device = (Device *)arg;
    char tmpBuff[128] = {0};

    /* 一直读串口有没有收到数据 */
    while (device->is_running)
    {
        /* 读取串口数据：注意数据格式为蓝牙帧格式 */
        ssize_t data_len = read(device->fd, tmpBuff, sizeof(tmpBuff));

        /* 数据处理 */
        if (data_len > 0 && device->post_read)
        {
            /* 数据转换（蓝牙帧->字符数组） */
            data_len = device->post_read(tmpBuff, data_len); /* parm1:蓝牙数据帧 parm2：帧长度 return:>=0 实际数据长度 -1 error */
            if (data_len == -1)
            {
                log_error("接收到的蓝牙数据不对");
                continue;
            }

            log_debug("字符数组为：%.*s", data_len, tmpBuff);

            /* 将字符数组数据放入上行缓冲 */
            app_buffer_write(device->up_buffer, tmpBuff, data_len);

            /* 注册线程池处理函数 */
            app_pool_register(pthreads_BlueTask, arg);
        }
    }
}

/**
 * @brief 在这里处理MQTT接收到的数据
 *
 * @param message
 */
void receive_MqttData_callback(MQTTClient_message *message)
{
    /*1.将json数据转换为字符数组 */
    char strbuff[128] = {0};
    app_message_json2chars(message->payload, strbuff);

    /* 2.将字符数组数据放入下行缓冲 */
    app_buffer_write(device->down_buffer, strbuff, strlen(strbuff));

    /*3.注册线程池处理函数 */
    app_pool_register(pthreads_MqttTask, device);
}

/*===============回调函数部分 下==============================================================*/

/**
 * @brief 初始化硬件模块
 *
 */
Device *app_device_init(char *filename)
{

    /* 0.初始化设备结构体 */
    device = (Device *)malloc(sizeof(Device));

    /* 1.打开设备文件 */
    device->filename = filename;
    device->fd = open(device->filename, O_RDWR);

    /* 2. 创建上行和下行缓冲区 */
    device->up_buffer = app_buffer_init(1024);
    device->down_buffer = app_buffer_init(1024);

    /* 3.初始化其他变量*/
    device->is_running = 0; /* 1为运行 */
    device->post_read = NULL;
    device->pre_write = NULL;

    /* 4.启动线程池 */
    app_pool_init(10);

    /* 5.启动MQTT服务器 */
    app_mqtt_init();

    return device;
}

/**
 * @brief 启动程序
 *
 */
returnType_t app_device_start(Device *device)
{
    if (device && device->is_running)
    {
        log_debug("设备已经在运行");

        return SUCCESS;
    }

    /* 1.开启读取线程：通过串口接收下行设备信息（BL)发送到上行缓存  */
    int result = pthread_create(&device->read_threadID, NULL, receive_BlueData_callback, device);
    if (result == -1)
    {
        log_error("创建读线程失败");
        return ERROR;
    }

    /* 2.注册MQTT回调函数：通过MQTT接收上行设备信息发送到下行缓存   */
    if (app_mqtt_regRecvCb(receive_MqttData_callback) == ERROR)
    {
        log_error("注册MQTT回调函数失败");
        return ERROR;
    }

    /* 3.置位运行态 */
    device->is_running = 1; /* 1为运行 */

    return SUCCESS;
}

/**
 * @brief 关闭程序
 *
 */

returnType_t app_device_stop(Device *device)
{
    /* 释放两个缓冲区 */
    free(device->up_buffer);
    free(device->down_buffer);

    /* 取消运行态 */
    device->is_running = 0;

    /* 删除读线程 */
    pthread_cancel(device->read_threadID);
    pthread_join(device->read_threadID, NULL);

    /* 关闭串口文件  */
    close(device->fd);

    /* 关闭MQTT服务器 */
    app_mqtt_close();

    /* 删除线程池 */
    app_pool_destroy();

    /* 释放设备结构体 */
    free(device);

    return SUCCESS;
}
